/*
Pyxis 2.0
Copyright 2010-2011 Thomas W. Holtquist

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

using System;
using System.Threading;

using Microsoft.SPOT;

using Skewworks.Pyxis;

namespace Skewworks.Pyxis.GUI.Controls
{

    #region Event Delegates

    [Serializable]
    public delegate void OnTap(object sender, point e);

    [Serializable]
    public delegate void OnTapHold(object sender, point e);

    [Serializable]
    public delegate void OnFormTap(point e);

    [Serializable]
    public delegate void OnNodeTap(TreeviewNode node, point e);

    [Serializable]
    public delegate void OnNodeExpanded(object sender, TreeviewNode node);

    [Serializable]
    public delegate void OnNodeCollapsed(object sender, TreeviewNode node);

    [Serializable]
    public delegate void OnSelectedIndexChange(object sender, int index);

    [Serializable]
    public delegate void OnSelectedFileChanged(object sender, string path);

    [Serializable]
    public delegate void OnTextChanged(object sender);

    [Serializable]
    public delegate void OnVirtualKeyboardClosed(object sender);

    [Serializable]
    public delegate void OnValueChanged(object sender, int value);

    #endregion

    [Serializable]
    public class Control : MarshalByRefObject
    {

        #region Variables
        
        protected internal int _xOffset;                // Used for placement inside containers like Forms & Panels
        protected internal int _yOffset;                // Used for placement inside containers like Forms & Panels

        protected internal int _x;
        protected internal int _y;
        protected internal int _w;
        protected internal int _h;
        protected internal bool _visible = true;
        protected internal bool _enabled = true;
        protected internal bool _mDown = false;
        protected internal Control _parent;
        protected internal bool _suspend = false;
        protected internal object _tag;

        protected internal TapState _eTapHold;          // TapHold used to wait for ContextMenus
        protected internal point _ptTapHold;

        #endregion

        #region Events

        public event OnTap tapEvent;

        /// <summary>
        /// Event for Taps
        /// </summary>
        /// <param name="sender"></param>
        protected virtual void OnTap(object sender, point e)
        {
            if (tapEvent != null)
                tapEvent(sender, e);
        }

        public event OnTapHold TapHold;

        /// <summary>
        /// Event for Tap & Hold
        /// </summary>
        /// <param name="sender"></param>
        protected virtual void OnTapHold(object sender, point e)
        {
            if (TapHold != null) TapHold(sender, e);
        }

        #endregion

        #region Touch Methods

        public virtual void TouchDown(object sender, point e)
        {
            if (!_enabled || !_visible)
                return;

            _mDown = true;

            // Begin TapHold
            _ptTapHold = e;
            _eTapHold = TapState.THWaiting;
            Thread thHold = new Thread(TapHoldWaiter);
            thHold.Start();

        }

        public virtual void TouchUp(object sender, point e)
        {
            if (!_enabled || !_visible) return;

            // Check Tap Hold
            if (_eTapHold == TapState.THComplete)
            {
                _eTapHold = TapState.Normal;
                return;
            }

            // Perform normal tap
            if (_mDown)
            {
                if (this.ScreenBounds.contains(e)) OnTap(this, new point(e.X - Left, e.Y - Top));
                _mDown = false;
            }
        }

        public virtual void TouchMove(object sender, point e)
        {
            // Do nothing
        }

        private void TapHoldWaiter()
        {
            Thread.Sleep(750);
            if (_eTapHold == TapState.Normal)
                return;

            OnTapHold(this, _ptTapHold);
        }

        #endregion

        #region  Properties

        public virtual rect Bounds
        {
            get { return new rect(_x, _y, _w, _h); }
            set { }
        }

        public virtual bool Enabled
        {
            get { return _enabled; }
            set 
            { 
                _enabled = value; 
                Render(true); 
            }
        }

        public virtual int Height
        {
            get { return _h; }
            set
            {
                if (value < 30) value = 30;
                _h = value;
                if (_parent != null) _parent.Render();
            }
        }

        public virtual int Left
        {
            get { return _x + _xOffset; }
        }

        public virtual Control Parent
        {
            get { return _parent; }
            set { _parent = value; }
        }

        public virtual bool PenDown
        {
            get { return _mDown; }
        }

        public virtual rect ScreenBounds
        {
            get { return new rect(_x + _xOffset, _y + _yOffset, _w, _h); }
        }

        public virtual Bitmap ScreenBuffer
        {
            get { return (_parent == null) ? null : _parent.ScreenBuffer; }
        }

        public virtual bool Suspended
        {
            get { return _suspend; }
            set
            {
                _suspend = value;
                if (!_suspend && _parent != null) 
                    _parent.Render();
            }
        }

        public virtual object Tag
        {
            get { return _tag; }
            set { _tag = value; }
        }

        public virtual int Top
        {
            get { return _y + _yOffset; }
        }

        public virtual Control TopLevelContainer
        {
            get
            {
                if (_parent == null)
                    return null;
                return _parent.TopLevelContainer;
            }
        }

        public virtual bool Visible
        {
            get { return _visible; }
            set 
            { 
                _visible = value;
                //if (_parent != null) _parent.Render();
            }
        }

        public virtual int Width
        {
            get { return _w; }
            set 
            { 
                _w = value; 
                if (_parent != null) 
                    _parent.Render();
            }
        }

        public virtual int X
        {
            get { return _x; }
            set 
            {
                _x = value; 
                if (_parent != null)
                    _parent.Render();
            }
        }

        public virtual int Y
        {
            get { return _y; }
            set 
            { 
                _y = value; 
                if (_parent != null) 
                    _parent.Render();
            }
        }

        #endregion

        #region Public Methods

        public virtual void SetOffset(Control sender, point e)
        {
            if (sender != _parent) 
                throw new Exception("Only a parent can set a child's offset");
            _xOffset = e.X;
            _yOffset = e.Y;
        }

        #endregion

        #region GUI

        public virtual void Render()
        {
            Render(false);
        }

        public virtual void Render(bool flush)
        {
        }

        #endregion

    }
}
